/* BASE ONLY -- USES CUSTOM DETECTION
 * alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (msg:"WEB-CLIENT Microsoft Internet Explorer EMF polyline overflow attempt"; flow:to_client,established; flowbits:isset,file.emf; content:" EMF"; content:"|01 00 00 00|"; distance:-44; within:4; metadata:service http, policy security-ips drop, policy balanced-ips drop; reference:cve,2009-0081; reference:url,technet.microsoft.com/en-us/security/bulletin/ms09-006; classtype:attempted-user; sid:15300;)
*/
/*
 * Use at your own risk.
 *
 * Copyright (C) 2005-2008 Sourcefire, Inc.
 * 
 * This file is autogenerated via rules2c, by Brian Caswell <bmc@sourcefire.com>
 */

#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util.h"

//#define DEBUG
#ifdef DEBUG
#define DEBUG_WRAP(code) code
#else
#define DEBUG_WRAP(code)
#endif

/* declare detection functions */
int rule15300eval(void *p);

/* declare rule data structures */
/* precompile the stuff that needs pre-compiled */
/* flow:established, to_client; */
static FlowFlags rule15300flow0 = 
{
    FLOW_ESTABLISHED|FLOW_TO_CLIENT
};

static RuleOption rule15300option0 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule15300flow0
    }
};
/* flowbits:isset "file.emf"; */
static FlowBitsInfo rule15300flowbits1 =
{
    "file.emf",
    FLOWBIT_ISSET,
    0,
};

static RuleOption rule15300option1 =
{
    OPTION_TYPE_FLOWBIT,
    {
        &rule15300flowbits1
    }
};
// content:" EMF", depth 0; 
static ContentInfo rule15300content2 = 
{
    (uint8_t *) " EMF", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule15300option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule15300content2
    }
};
// content:"|01 00 00 00|", offset -44, depth 4, relative; 
static ContentInfo rule15300content3 = 
{
    (uint8_t *) "|01 00 00 00|", /* pattern (now in snort content format) */
    4, /* depth */
    -44, /* offset */
    CONTENT_RELATIVE|CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule15300option3 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule15300content3
    }
};

/* references for sid 15300 */
/* reference: cve "2009-0081"; */
static RuleReference rule15300ref1 = 
{
    "cve", /* type */
    "2009-0081" /* value */
};

/* reference: url "technet.microsoft.com/en-us/security/bulletin/ms09-006"; */
static RuleReference rule15300ref2 = 
{
    "url", /* type */
    "technet.microsoft.com/en-us/security/bulletin/ms09-006" /* value */
};

static RuleReference *rule15300refs[] =
{
    &rule15300ref1,
    &rule15300ref2,
    NULL
};
/* metadata for sid 15300 */
/* metadata:service http, policy balanced-ips drop, policy security-ips drop; */
static RuleMetaData rule15300service1 = 
{
    "service http"
};


//static RuleMetaData rule15300policy1 = 
//{
//    "policy balanced-ips drop"
//};
//
//static RuleMetaData rule15300policy2 = 
//{
//    "policy security-ips drop"
//};


static RuleMetaData *rule15300metadata[] =
{
    &rule15300service1,
//    &rule15300policy1,
//    &rule15300policy2,
    NULL
};
RuleOption *rule15300options[] =
{
    &rule15300option0,
    &rule15300option1,
    &rule15300option2,
    &rule15300option3,
    NULL
};

Rule rule15300 = {
   
   /* rule header, akin to => tcp any any -> any any               */{
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "$HTTP_PORTS", /* SRCPORT   */
   
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
   
       "any", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid (HARDCODED!!!) */
       15300, /* sigid */
       9, /* revision */
   
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "BROWSER-IE Microsoft Internet Explorer EMF polyline overflow attempt",     /* message */
       rule15300refs /* ptr to references */
       ,rule15300metadata
   },
   rule15300options, /* ptr to rule options */
   &rule15300eval, /* use custom detection function */
   0 /* am I initialized yet? */
};


/* detection functions */

int rule15300_CheckPoints(const uint8_t *cursor_detect, uint32_t pointCount, const uint8_t *end_of_payload) {
   uint32_t i;

   DEBUG_WRAP(printf("rule15300_CheckPoints checking %d points\n", pointCount));

   for(i = 0; i < pointCount; i++) {

      if(cursor_detect + 4 >= end_of_payload)
         return(0);

      DEBUG_WRAP(printf("X=|%02x %02x %02x %02x|\n", *cursor_detect, *(cursor_detect+1), *(cursor_detect+2), *(cursor_detect+3)));

      // Check if X > 0x0FFFFFFF (little endian)
      if(*(cursor_detect + 3) > 0x0F)
         return(1);

      if(cursor_detect + 8 >= end_of_payload)
         return(0);

      DEBUG_WRAP(printf("Y=|%02x %02x %02x %02x|\n", *(cursor_detect+4), *(cursor_detect+5), *(cursor_detect+6), *(cursor_detect+7)));

      // Check if Y > 0x0FFFFFFF (little endian)
      if(*(cursor_detect + 7) > 0x0F)
         return(1);

      cursor_detect += 8;
   }

   return(0);
}


int rule15300eval(void *p) {
   const uint8_t *cursor_normal = 0, *beg_of_payload, *end_of_payload;
   SFSnortPacket *sp = (SFSnortPacket *) p;
   const uint8_t *tmp_ptr;

   const uint8_t *cursor_detect;
   uint32_t recordSize;
   uint32_t pointCount, polylineCount; 

   DEBUG_WRAP(printf("rule15300eval enter\n"));

   if(sp == NULL)
      return RULE_NOMATCH;

   if(sp->payload == NULL)
      return RULE_NOMATCH;
    
   // flow:established, to_client;
   if(checkFlow(p, rule15300options[0]->option_u.flowFlags) <= 0)
      return RULE_NOMATCH;

   // flowbits:isset "file.emf";
   if(processFlowbits(p, rule15300options[1]->option_u.flowBit) <= 0)
      return RULE_NOMATCH;

   // content:" EMF", depth 0;
   if(contentMatch(p, rule15300options[2]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;

   // content:"|01 00 00 00|", offset -44, depth 4, relative;
   if(contentMatch(p, rule15300options[3]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;

   // Extract the size of the header and jump
   recordSize = read_little_32_inc(cursor_normal);

   tmp_ptr = cursor_normal + recordSize - 8;

   if(tmp_ptr < cursor_normal) // Int overflow check
      return RULE_NOMATCH;

   cursor_normal = tmp_ptr;

   if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
      return RULE_NOMATCH;

   // Now jump records until we find "|04 00 00 00|" (EMR_POLYLINE record)
   while(cursor_normal + 12 <= end_of_payload) {

      DEBUG_WRAP(printf("TAG: |%02x %02x %02x %02x|\n", *cursor_normal, *(cursor_normal+1), *(cursor_normal+2), *(cursor_normal+3)));

      if(*cursor_normal == 0x0e) {

         if(*(cursor_normal + 1) == 0x00 && *(cursor_normal + 2) == 0x00 && *(cursor_normal + 3) == 0x00) {
            // End of File record
            DEBUG_WRAP(printf("End-of-File\n"));
            return RULE_NOMATCH;
         }

      } else if(*cursor_normal == 0x04) {

         if(*(cursor_normal + 1) == 0x00 && *(cursor_normal + 2) == 0x00 && *(cursor_normal + 3) == 0x00) {

            // we found an EMR_POLYLINE record (0x00000004)
            if(cursor_normal + 32 >= end_of_payload) // tag header stuff, pointCount, and first poly check
               return RULE_NOMATCH;

            cursor_detect = cursor_normal + 4 + 4 + 16; // tag, size, struct RECTL Bounds
            
            pointCount = read_little_32_inc(cursor_detect);

            if(rule15300_CheckPoints(cursor_detect, pointCount, end_of_payload))
               return RULE_MATCH;
         }

      } else if(*cursor_normal == 0x07) {

         if(*(cursor_normal + 1) == 0x00 && *(cursor_normal + 2) == 0x00 && *(cursor_normal + 3) == 0x00) {

            // we found an EMR_POLYPOLYLINE record (0x00000007)
            if(cursor_normal + 32 >= end_of_payload) // tag header stuff, polylineCount, and pointCount
               return RULE_NOMATCH;

            cursor_detect = cursor_normal + 4 + 4 + 16; // tag, size, struct RECTL Bounds

            polylineCount = read_little_32_inc(cursor_detect);
            pointCount = read_little_32_inc(cursor_detect);

            tmp_ptr = cursor_detect + (polylineCount * 4); // Skip over aPolylinePointCount array
            if(tmp_ptr < cursor_detect) // Int overflow check
               return RULE_NOMATCH;

            cursor_detect = tmp_ptr;

            // Function checks cursor upper bounds
            if(rule15300_CheckPoints(cursor_detect, pointCount, end_of_payload))
               return RULE_MATCH;
         }

      }

      // Not an interesting record.  Skip and loop.
      recordSize = read_little_32(cursor_normal + 4);

      DEBUG_WRAP(printf("looping, jumping recordSize = 0x%08x bytes\n", recordSize));

      tmp_ptr = cursor_normal + recordSize;

      if(tmp_ptr < cursor_normal || recordSize == 0) // Int overflow and sanity checking
         return RULE_NOMATCH;

      cursor_normal = tmp_ptr;
   }

   return RULE_NOMATCH;
}

/*
Rule *rules[] = {
    &rule15300,
    NULL
};
*/

